//
// Created by antler on 2018/12/6.
//

#ifndef LUA_SCREEN_H
#define LUA_SCREEN_H

#include <string>
#include <vector>

#include "luaext/size/Size.h"
#include "luaext/image/Image.h"
#include "luaext/color3b/Color3B.h"
#include "luaext/color3f/Color3F.h"

#define CLASSNAME_SCREEN "screen"
#define USERTYPE_SCREEN "screen"

#define FUZZINESS_DEFAULT (100)
#define QUALITY_DEFAULT (100)
#define LIMIT_DEFAULT (200)

class Screen {
public:
    enum {
        LANDSCAPE_RIGHT = 1,
        LANDSCAPE_LEFT = 2,
        PORTRAIT = 3,
    };

    enum {
        PRIORITY_LEFT_FIRST = 0x1000,
        PRIORITY_RIGHT_FIRST = 0x1001,
        PRIORITY_UP_FIRST = 0x2000,
        PRIORITY_DOWN_FIRST = 0x2010,
        PRIORITY_HORIZONTAL_FIRST = 0x4000,
        PRIORITY_VERTICAL_FIRST = 0x4100,
        PRIORITY_DEFAULT = PRIORITY_LEFT_FIRST | PRIORITY_UP_FIRST | PRIORITY_HORIZONTAL_FIRST,
    };

    enum {
        MOCK_NONE = 0,
        MOCK_INPUT = 1,
        MOCK_OUTPUT = 2,
        MOCK_BOTH = 3,
    };

    using POINT_LIST = std::vector<Point>;

    typedef struct ColorItem {
        int x;
        int y;
        int color;
        int offset;
        int fuzz;
    } ColorItem;

    using COLOR_LIST = std::vector<ColorItem>;

public:
    static Screen *getInstance();

    static void releaseInstance();

    Screen();

    ~Screen();

    // 初始化屏幕参数
    void init(int orientation);

    // 获取屏幕分辨率尺寸
    Size getSize();

    // 获取屏幕DPI
    int getDPI();

    // 截取屏幕范围为rect的图像，并返回Image类型
    Image *capture(const Rect &rect = Rect::ZERO);

    // 保持屏幕内容
    void keep(bool value);

    bool isKeepScreenCapture() const;

    // 获取当前设备的屏幕方向
    // 注意该函数返回值仅和当前设备物理转向有关，并非返回screen.init设定的值。
    int getOrientation();

    // 截图并保存至本地
    // 实时截图屏幕rect范围（不指定或rect = Rect(0, 0, 0, 0)表示全屏范围）的图像并保存至path路径，可选quality为图片质量（取值范围0-100），截图成功返回true，失败返回false（例如指定路径无权限访问）。
    // 注意path路径只能是jpg/png后缀结尾。
    bool snapshot(const std::string &filePath, const Rect &rect, int quality);

    // 获取屏幕颜色值
    bool getColor(const Point &pos, Color3B &c3b);

    // 比较颜色值/序列
    // globalFuzz指定全局模糊度，注意以下两点：
    // colors序列中存在fuzz参数时，优先使用指定的fuzz作为模糊度对当前colors序列进行查找，忽略globalFuzz设置；
    // colors序列中存在offset参数时，优先使用指定的offset作为偏色值对当前colors序列进行查找，忽略fuzz和globalFuzz设置
    bool matchColors(const std::string &colors, int globalFuzz);

    // 查找图像
    // 根据指定的屏幕范围rect中，查找image指定的图像，可选fuzzness指定模糊度（范围0-100，默认100），可选priority指定搜索优先级，返回第一个找到的坐标，查找失败返回Point.INVALID。
    Point findImage(const Rect &rect, const std::string &path, int fuzziness, int priority,
                    int ignoreColor);

    Point findImage(const Rect &rect, const Image &image, int fuzziness, int priority,
                    int ignoreColor);

    // 查找所有颜色值/序列坐标
    // 根据指定的屏幕范围rect中，查找color色值或序列的坐标值，可选globalFuzz指定全局模糊度（范围0-100，默认100），可选priority指定搜索优先级，返回rect范围内所有符合条件的点（最多不超过limit个），查找失败返回Point.INVALID。
    POINT_LIST
    findColors(const Rect &rect, const std::string &colors, int globalFuzz, int priority,
               int limit);

    // 设置转换模式
    void setMockMode(int mode);

    // 设置转换回调函数
    // 配合screen.setMockMode使用，设置转换函数，用于脚本对多分辨率的支持，通过该函数开发者可以对脚本运行过程中其他函数传入、返回的rect数据进行修改，返回修改后的值。
    void setMockTransform();

protected:
    bool captureScreen();

    void releaseScreenCapture();

    bool isScreenCapture();

    bool takeScreenCapture();

    bool checkColor(void *addrPtr, int x, int y, const COLOR_LIST &colorList, int globalFuzz);


protected:
    int mOrientation;
    bool mbKeepCapture;
    Image *mScreenCapture;
    int mMockMode;

protected:
    static Screen *g_pScreen;
};


#endif //LUA_SCREEN_H
